#include "InterprocessCommunication.h"

InterprocessCommunication::InterprocessCommunication(u32 recvPort, u32 sendPort, const QString& localIP, QObject* parent)
    : QObject(parent), m_recvPort(recvPort), m_sendPort(sendPort), m_localIP(localIP)
{
    // 创建 UDP 套接字
    m_socket = new QUdpSocket(this);

    // 绑定到指定的接收端口，允许共享地址
    if (!m_socket->bind(QHostAddress(localIP), recvPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) {
        qDebug() << "IPC绑定端口失败：" << recvPort;
    }
    else
    {
        qDebug() << "IPC绑定端口成功";
    }

    // 连接 readyRead 信号，用于接收数据
    connect(m_socket, &QUdpSocket::readyRead, this, &InterprocessCommunication::readPendingDatagrams);
}

InterprocessCommunication::~InterprocessCommunication()
{

}

void InterprocessCommunication::sendCommand(u8 cmdID, QVariant data)
{
    // 构造并发送对应的指令消息
    QByteArray message = constructSendingMessage(cmdID, data);

    // 循环五次，每次增加10ms延迟
    for (int i = 0; i < 5; ++i)
    {
        QTimer::singleShot(i * 10, this, [=]() {
            writeDatagram(message);
        });
    }
}

void InterprocessCommunication::writeDatagram(QByteArray message)
{
    printQByteArrayHex(message);
    // 发送UDP消息到指定端口
    m_socket->writeDatagram(message, QHostAddress(m_localIP), m_sendPort);
}

void InterprocessCommunication::readPendingDatagrams()
{
    while (m_socket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(m_socket->pendingDatagramSize());

        // 接收数据
        QHostAddress sender;
        u16 senderPort;
        m_socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);

        // 打印接收到的十六进制数据
        printQByteArrayHex(datagram);

        // 检查数据的最小长度（1字节Head + 2字节Length + 1字节MsgID + 4字节CRC32 = 8字节）
        if (datagram.size() < 8) {
            qDebug() << "数据包长度不足";
            return;
        }

        // 手动解析数据
        IPCProtocol protocol;
        const u8* data = reinterpret_cast<const u8*>(datagram.data());

        protocol.Head = data[0];  // 帧头
        protocol.Length = static_cast<u16>(data[1] | (data[2] << 8));  // 长度
        protocol.MsgID = data[3];  // 消息ID

        // 检查Length是否合理
        if (protocol.Length != datagram.size()) {
            qDebug() << "数据包长度不匹配";
            return;
        }

        // 拷贝Payload
        int payloadSize = protocol.Length - 8; // 扣除帧头、长度、消息ID、校验码
        memcpy(protocol.Payload, &data[4], payloadSize);

        // 提取CRC32
        protocol.Crc32 = static_cast<u32>(data[protocol.Length - 4] | (data[protocol.Length - 3] << 8) |
                                          (data[protocol.Length - 2] << 16) | (data[protocol.Length - 1] << 24));

        // 计算CRC32
        u32 calc_crc = processCrc32Accumulate(reinterpret_cast<const u8*>(data), protocol.Length - 4);

        // 校验CRC32
        if (protocol.Crc32 != calc_crc) {
            qDebug() << "接收到的进程消息校验码不匹配!" << "接收到的CRC32：" << protocol.Crc32 << "计算的CRC32：" << calc_crc;
            return;
        }

        // 解析消息 ID 并处理
        switch (protocol.MsgID)
        {
        case IPC_MSG_EMERGESTOP_BUTTON_STATUS:  // 0x81 急停按键状态
        {
            IPC_MSG_EmergeStopButtonStatus* buttonStatus = reinterpret_cast<IPC_MSG_EmergeStopButtonStatus*>(protocol.Payload);
            qDebug() << "接收到急停按键状态:" << buttonStatus->buttonStatus;
            //emit buttonStateReceived(buttonStatus->buttonStatus);
        }
        break;

        default:
        {
            qDebug() << "未知进程消息ID：" << protocol.MsgID;
        }
        break;
        }
    }
}

QByteArray InterprocessCommunication::constructSendingMessage(u8 cmdID, const QVariant &data)
{
    QByteArray message;
    QByteArray payload;  // 动态存储Payload
    IPCProtocol protocol;
    protocol.Head = 0xFE;  // 固定帧头
    protocol.MsgID = cmdID;

    // 根据不同的命令构造 Payload 数据
    switch (cmdID)
    {
    case IPC_CMD_TAKEOVER_STATUS:  // 0x80 夺权状态
    {
        IPC_CMD_TakeoverStatus takeoverStatus;
        if(data == 0)   // 不夺权
        {
            takeoverStatus.takeoverStatus = 0x0;
        }
        else if(data == 1)  // 夺权
        {
            takeoverStatus.takeoverStatus = 0x1;
        }
        payload.append(reinterpret_cast<const char*>(&takeoverStatus), sizeof(takeoverStatus));
    }
    break;

    default:
    {
        qDebug() << "未知进程指令：" << cmdID;
        return message;  // 返回空消息
    }
    break;
    }

    // 计算总长度：帧头 + 长度 + 消息ID + Payload长度 + CRC32长度
    protocol.Length = sizeof(protocol.Head) + sizeof(protocol.Length) + sizeof(protocol.MsgID) + payload.size() + sizeof(protocol.Crc32);

    // 组装消息
    message.append(reinterpret_cast<const char*>(&protocol.Head), sizeof(protocol.Head));
    message.append(reinterpret_cast<const char*>(&protocol.Length), sizeof(protocol.Length));
    message.append(reinterpret_cast<const char*>(&protocol.MsgID), sizeof(protocol.MsgID));
    message.append(payload);  // 添加Payload

    // 计算并填充校验码（基于消息的前部分，校验码不包括在内）
    u32 crc = processCrc32Accumulate(reinterpret_cast<const u8*>(message.data()), static_cast<u32>(message.size()));
    message.append(reinterpret_cast<const char*>(&crc), sizeof(crc));  // 添加校验码

    return message;
}


u32 InterprocessCommunication::processCrc32Accumulate(const u8* buf, u32 len)
{
    u32       reCrc = 0xFFFFFFFF;
    u32       temp  = 0;
    u8        cnt   = 0;
    const u8* ptr   = buf;

    const u32 xCode = 0x04C11DB7;
    u32       xbit  = 0x80000000;
    while (len > 0)
    {
        xbit = 0x80000000;
        temp = 0;
        cnt  = static_cast<u8>((len > 4) ? 4 : len);
        for (s32 j = 0; j < cnt; j++)
        {
            temp |= static_cast<u32>(ptr[j] << (8 * j));
        }

        for (s32 bit = 0; bit < 32; bit++)
        {
            if ((reCrc & 0x80000000) != 0)
            {
                reCrc <<= 1;
                reCrc  ^= xCode;
            }
            else
            {
                reCrc <<= 1;
            }
            if ((temp & xbit) != 0)
            {
                reCrc ^= xCode;
            }
            xbit >>= 1;
        }
        ptr += cnt;
        len -= cnt;
    }

    return reCrc;
}

void InterprocessCommunication::printQByteArrayHex(const QByteArray &data)
{
    QString hexData;
    for (const auto& byte : data) {
        hexData.append(QString("%1 ").arg(static_cast<u8>(byte), 2, 16, QLatin1Char('0')).toUpper());
    }
    qDebug() << "数据 (十六进制):" << hexData.trimmed();
}
